
#encoding: latin-1

from PyQt4.QtGui import *
from PyQt4.QtCore import *
from Ui_Othello import *
from Plateau import *

# Chemins vers les images
grid_empty_img = QString("resources/grid_empty.jpg")
grid_white_img = QString("resources/grid_white.jpg")
grid_black_img = QString("resources/grid_black.jpg")
main_white_img = QString("resources/main_white.png")
main_black_img = QString("resources/main_black.png")

class QtPlateau(QObject, Ui_MainWindow):
    """ Classe unique d'interface graphique :
        - Gère le chargement et l'affichage de l'interface
        - Reçoit et traite les instructions modifiant l'espace de jeu
        - Reçoit et traite les instructions basiques de démarrage - clôture du jeu et affichage du score. """
    
    def __init__(self, othello):
        """ Constructeur : charge les éléments d'interface puis affiche la fenêtre principale. """
        
        # constructeur de QObject
        QObject.__init__(self)
        
        # définir l'instance de fenêtre principale
        self.mainWindow = QWidget()
        
        # charger la fenêtre principale
        self.setupUi(self.mainWindow)
        self.mainWindow.show()
        
        # garder en mémoire l'instance othello
        self.othello = othello
        
        # charger les images des cases (Vide, Noir, Blanc)
        self.emptyIcon = QIcon(QPixmap(grid_empty_img))
        self.whiteIcon = QIcon(QPixmap(grid_white_img))
        self.blackIcon = QIcon(QPixmap(grid_black_img))
        
        # charger les images qui indiquent quel joueur a la main, dans la barre latérale.
        self.whiteMainImg = QPixmap(main_white_img)
        self.blackMainImg = QPixmap(main_black_img)
        
        # créer un tableau qui référence les cases
        self.cases = (None, None           , None           , None           , None           , None           , None           , None           , None           , None,
                      None, self.Ui_case_11, self.Ui_case_12, self.Ui_case_13, self.Ui_case_14, self.Ui_case_15, self.Ui_case_16, self.Ui_case_17, self.Ui_case_18, None,
                      None, self.Ui_case_21, self.Ui_case_22, self.Ui_case_23, self.Ui_case_24, self.Ui_case_25, self.Ui_case_26, self.Ui_case_27, self.Ui_case_28, None,
                      None, self.Ui_case_31, self.Ui_case_32, self.Ui_case_33, self.Ui_case_34, self.Ui_case_35, self.Ui_case_36, self.Ui_case_37, self.Ui_case_38, None,
                      None, self.Ui_case_41, self.Ui_case_42, self.Ui_case_43, self.Ui_case_44, self.Ui_case_45, self.Ui_case_46, self.Ui_case_47, self.Ui_case_48, None,
                      None, self.Ui_case_51, self.Ui_case_52, self.Ui_case_53, self.Ui_case_54, self.Ui_case_55, self.Ui_case_56, self.Ui_case_57, self.Ui_case_58, None,
                      None, self.Ui_case_61, self.Ui_case_62, self.Ui_case_63, self.Ui_case_64, self.Ui_case_65, self.Ui_case_66, self.Ui_case_67, self.Ui_case_68, None,
                      None, self.Ui_case_71, self.Ui_case_72, self.Ui_case_73, self.Ui_case_74, self.Ui_case_75, self.Ui_case_76, self.Ui_case_77, self.Ui_case_78, None,
                      None, self.Ui_case_81, self.Ui_case_82, self.Ui_case_83, self.Ui_case_84, self.Ui_case_85, self.Ui_case_86, self.Ui_case_87, self.Ui_case_88, None,
                      None, None           , None           , None           , None           , None           , None           , None           , None           , None)
        
        # assigner l'image de case vide aux diverses cases
        self.initPlateau()
        
        # connexion des boutons nouvelle partie / quitter
        qApp = QCoreApplication.instance()
        QObject.connect(self.Ui_bouton_jj, SIGNAL("clicked()"), self.initJoueurJoueur)
        QObject.connect(self.Ui_bouton_jo, SIGNAL("clicked()"), self.initJoueurOrdi)
        QObject.connect(self.Ui_bouton_oo, SIGNAL("clicked()"), self.initOrdiOrdi)
        QObject.connect(self.Ui_bouton_quitter, SIGNAL("clicked()"), qApp, SLOT("quit()"))
        
        self.plateauConnected = False
        
    def connectPlateau(self):
        """ Connection et mapping des signaux "clicked" des boutons. """
        
        self.plateauConnected = True
        self.mapper = QSignalMapper()
        for i in range(11,89) :
            if self.cases[i] != None :
                Ui_case = self.cases[i]
                QObject.connect(Ui_case, SIGNAL("clicked()"), self.mapper, SLOT("map()"))
                self.mapper.setMapping(Ui_case, i)
        QObject.connect(self.mapper, SIGNAL("mapped(int)"), self.jouerHumain)
        
    def disconnectPlateau(self):
        """ Déconnection du mapper, en cas de passage d'un mode J/J ou J/O au mode O/O. """
        
        if self.plateauConnected:
            QObject.disconnect(self.mapper, SIGNAL("mapped(int)"), self.jouerHumain)
    
    def initPlateau(self):
        """ Assigner l'image de case vide aux diverses cases. """
        
        for i in range(11,89):
            if self.cases[i] != None:
                if self.othello.plateau.grille[i] == 0:
                    self.cases[i].setIcon(self.emptyIcon)
                elif self.othello.plateau.grille[i] == 1:
                    self.cases[i].setIcon(self.whiteIcon)
                elif self.othello.plateau.grille[i] == 2:
                    self.cases[i].setIcon(self.blackIcon)
        
    def initJoueurJoueur(self):
        """ Initialise une partie joueur contre joueur. """
        
        if self.afficheDialogConfirmerNouvellePartie():
            self.othello.Initialisation("jj")
            self.initPlateau()
            self.connectPlateau()
        
    def initJoueurOrdi(self):
        """ Initialise une partie joueur contre ordinateur. """
        
        if self.afficheDialogConfirmerNouvellePartie():
            self.othello.Initialisation("jo")
            self.initPlateau()
            self.connectPlateau()
    
    def initOrdiOrdi(self):
        """ Initialise une partie ordinateur contre ordinateur. """
        
        if self.afficheDialogConfirmerNouvellePartie():
            self.othello.Initialisation("oo")
            self.initPlateau()
            self.disconnectPlateau()
            self.othello.partieOrdiVsOrdi()
        
    def jouerHumain(self, coup):
        """ Appelée par un clic de l'humain sur le plateau de jeu."""
                
        # Si le coup joué n'est pas acceptable, il ne se passe rien : le joueur doit simplement cliquer ailleurs.
        # Si le coup joué est acceptable...
        if self.othello.plateau.coupAcceptable(coup, self.othello.joueurMain.joueur):
            # ... jouer le coup
            self.othello.plateau.coup(coup, self.othello.joueurMain.joueur)
            # Mise à jour GUI
            self.updateCases()
            self.updateScore()
            # on donne la main à l'autre joueur
            self.othello.changeJoueurMain()
       
    def updateCases(self):
        """ Met à jour les cases du plateau graphique après chaque coup des deux joueurs. """
        
        for i in range(11, 89):
            if self.cases[i] != None:
                if self.othello.plateau.grille[i] == 0:
                    self.cases[i].setIcon(self.emptyIcon)
                elif self.othello.plateau.grille[i] == 1:
                    self.cases[i].setIcon(self.whiteIcon)
                elif self.othello.plateau.grille[i] == 2:
                    self.cases[i].setIcon(self.blackIcon)
        
    def updateScore(self):
        """ Met à jour l'affichage du score. """
        
        b, n = self.othello.plateau.score()
        self.Ui_label_scoreBlanc.setNum(b)
        self.Ui_label_scoreNoir.setNum(n)
        
    def updateMain(self):
        """ Met à jour l'affichage du joueur ayant la main. """
        
        if self.othello.joueurMain.joueur == 1:
            self.Ui_label_main.setPixmap(self.whiteMainImg)
        elif self.othello.joueurMain.joueur == 2:
            self.Ui_label_main.setPixmap(self.blackMainImg)
        
    def afficheDialogFinPartie(self):
        """ Génère et ouvre une boîte de dialogue en fin de partie, qui indique le gagnant et le score. """
        
        b, n = self.othello.plateau.score()
        box = QMessageBox()
        box.setWindowTitle(QString("Partie terminée !"))
        if b > n:
            message = "Joueur Blanc gagne !\nScore : Blanc " + b.__str__() + " - " + n.__str__() + " Noir"
            box.setText(QString(message))
        elif b < n:
            message = "Joueur Noir gagne !\nScore : Blanc " + b.__str__() + " - " + n.__str__() + " Noir"
            box.setText(QString(message))
        else :
            message = "Egalite !\nScore : Blanc " + b.__str__() + " - " + n.__str__() + " Noir"
            box.setText(QString(message))
        box.exec_()
        
    def afficheDialogConfirmerNouvellePartie(self):
        """ Génère et ouvre une boîte de dialogue pour demander à l'utilisateur de confirmer s'il veut recommencer une partie, lorsqu'il a cliqué, en cours d'une partie, sur l'un des boutons de nouvelle partie. Renvoie la réponse de l'utilisateur. """
        if self.othello.plateau.score() != (0,0) and self.othello.plateau.score() != (2,2):
            box = QMessageBox()
            box.setWindowTitle(QString("Nouvelle partie"))
            box.addButton(QMessageBox.Cancel)
            box.addButton(QMessageBox.Ok)
            box.setDefaultButton(QMessageBox.Ok)
            box.setText("Une partie est en cours. Etes-vous sur de vouloir commencer une nouvelle partie ?")
            if box.exec_() == QMessageBox.Ok:
                return True
            else: return False
        else: return True
        
        
        
        
        
    